(小ネタ) terraform graph で該当するリソースだけ絞り込むスクリプト
お疲れ様です。小島です。
terraform のリソースは増えていくにつれ、関係性について把握が難しくなるのではないでしょうか。
その時、依存関係を dot 言語で出力してくれる terraform graph
があります。
しかし、多くのリソースが含まれる図には多くの関係を示す線が含まれており、把握するには一苦労です。
terraform graph
には module-depth
という深さを指定し、出力を絞り込むことができるオプションがあります。
ですが、スモールスタートでの開発で徐々にリソースが増えていくような場合だと、 module のリファクタリングは state も考慮する必要があるので後回しになりがちです。
なので、正規表現に該当するリソースだけ吐き出すようなスクリプトを go で書きました。
スクリプト
スクリプトの使い方
# Glue に関するリソースを絞り込む terraform graph | go run . -expr "aws_glue_" | dot -Tsvg > graph_sample1.svg # Tempura に関するリソースを絞り込んだ後、再度 S3 に紐づくリソースを絞り込む terraform graph | go run . -expr "tempura" | go run . -expr "aws_s3_" | dot -Tsvg > graph_sample2.svg
実行結果
絞り込む前のグラフです。
Glue に関するリソースを絞り込んだ結果です。
はい、ジョブの数は 1 つ、クローラーと S3 バケットが 1-1 になっている構成です。あっています。
Tempura と S3 に紐づくリソースを絞り込んだ結果です。
pheasant_tempura_okonomiyaki
のバケットだけ aws リソースに紐づいていません。
アプリケーションでのみ使っているようです。なるほど。。。
確認した環境
# uname -a Darwin HL00566.local 19.3.0 Darwin Kernel Version 19.3.0: Thu Jan 9 20:58:23 PST 2020; root:xnu-6153.81.5~1/RELEASE_X86_64 x86_64 # terraform version Terraform v0.12.6 # go version go version go1.14 darwin/amd64 # dot -V dot - graphviz version 2.42.3 (20191010.1750)
スクリプトの解説
dot 言語の解析と出力には https://gonum.org のライブラリを使用しました。
数値計算用ライブラリ、とのことですが、グラフ言語に関するコードも入っていました。
- https://github.com/gonum/gonum/tree/v0.7.0/graph/encoding
- https://github.com/gonum/gonum/tree/v0.7.0/graph/formats
package main import ( // ... "gonum.org/v1/gonum/graph/formats/dot" "gonum.org/v1/gonum/graph/formats/dot/ast" )
dot.Parse
をすることで AST に解析してくれます。
dast, err := dot.Parse(os.Stdin)
AST を再構築しても良いですが、今回は各要素を直接書き換えることで対応しました。
case *ast.Subgraph: // ... xs := xt.Stmts xsSize := len(xs) delCnt := 0 for i := 0; i < xsSize; i++ { xtx := xs[i-delCnt] err := walk(xtx, f) // ... } xt.Stmts = xs // ...
type visitor struct { *regexp.Regexp } func (v *visitor) Visit(x ast.Stmt) error { switch xt := x.(type) { case *ast.NodeStmt: if v.MatchString(xt.Node.ID) { xt.Attrs = append(xt.Attrs, &ast.Attr{Key: "color", Val: "red"}) return nil } // ... } }
ast.Graph
の String()
で dot 言語形式で出力されます。
for _, g := range dast.Graphs { err := walk(g, v.Visit) if err != nil { log.Fatal(err) return } fmt.Println(g) }
感想
現状は理解するための可視化が目的だったので、この機能で満足しています。 次のアプローチとして node にアイコンを載せたり、依存関係を辿れるようにしたら楽しそうですね。